#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
任务调度器模块
负责动态调度用户在系统中创建的定时任务
"""

import logging
import os
from datetime import datetime
from celery import shared_task
from celery.schedules import crontab
from django.utils import timezone
from baojing.celery import app
from .models import ScheduledTask, TaskExecutionLog

logger = logging.getLogger(__name__)

# 从环境变量获取配置，默认为False
TASK_DEBUG_MODE = os.environ.get('TASK_DEBUG_MODE', 'False').lower() == 'true'


@shared_task
def check_and_schedule_tasks():
    """
    检查系统中所有定时任务，并根据需要添加或更新调度
    每分钟执行一次
    """
    try:
        logger.info("开始检查系统中的定时任务")
        
        # 获取当前配置模式
        is_eager_mode = app.conf.task_always_eager
        if TASK_DEBUG_MODE:
            logger.debug(f"当前任务执行模式: {'同步模式' if is_eager_mode else '异步模式'}")
            logger.debug(f"当前Beat调度配置: {app.conf.beat_schedule}")
        
        # 获取所有激活的定时任务
        active_tasks = ScheduledTask.objects.filter(is_active=True)
        logger.info(f"找到{len(active_tasks)}个激活的定时任务")
        
        # 当前已调度的任务
        current_schedules = set(app.conf.beat_schedule.keys())
        
        # 需要调度的任务
        scheduled_count = 0
        for task in active_tasks:
            # 生成唯一的任务ID
            task_key = f"scheduled-task-{task.id}"
            
            # 解析cron表达式
            cron_parts = task.cron_expression.strip().split()
            if len(cron_parts) != 5:
                logger.warning(f"任务{task.name}的cron表达式格式不正确: {task.cron_expression}")
                continue
            
            try:
                # 构建cron调度参数
                minute, hour, day_of_month, month_of_year, day_of_week = cron_parts
                
                # 更新或添加任务调度
                app.conf.beat_schedule[task_key] = {
                    'task': 'tasks.task_scheduler.execute_scheduled_task',
                    'schedule': crontab(
                        minute=minute,
                        hour=hour,
                        day_of_month=day_of_month,
                        month_of_year=month_of_year,
                        day_of_week=day_of_week
                    ),
                    'args': (task.id,)
                }
                scheduled_count += 1
                logger.info(f"已添加/更新任务调度: {task_key} (任务名: {task.name}, cron: {task.cron_expression})")
                
                # 从当前调度中移除，剩下的就是需要删除的
                if task_key in current_schedules:
                    current_schedules.remove(task_key)
            except Exception as e:
                logger.error(f"处理任务{task.name}时出错: {str(e)}")
        
        # 删除已经禁用或删除的任务调度
        removed_count = 0
        for task_key in current_schedules:
            # 只删除用户定义的任务，保留系统任务
            if task_key.startswith('scheduled-task-'):
                try:
                    del app.conf.beat_schedule[task_key]
                    removed_count += 1
                    logger.info(f"已移除任务调度: {task_key}")
                except Exception as e:
                    logger.error(f"移除任务调度{task_key}时出错: {str(e)}")
        
        logger.info(f"成功检查并调度了{scheduled_count}个定时任务，移除了{removed_count}个无效任务调度")
        
        # 无论在同步还是异步模式下，都可以检查是否有需要立即执行的任务
        # 这对于确保任务不会因为某些原因长时间未执行很有帮助
        now = timezone.now()
        for task in active_tasks:
            # 简单检查是否应该执行
            if TASK_DEBUG_MODE:
                logger.debug(f"检查任务 {task.name}: 当前时间 {now}, 最后执行时间 {task.last_executed_at}")
                
            # 任务检查逻辑独立于执行模式
            if task.last_executed_at is None:
                logger.info(f"任务 {task.name} 从未执行过，将按照计划执行")
            else:
                # 计算时间差（秒）
                time_diff = (now - task.last_executed_at).total_seconds()
                if TASK_DEBUG_MODE:
                    logger.debug(f"任务 {task.name} 上次执行时间差: {time_diff} 秒")
        
        # 异步模式下，让Beat按照cron表达式正常调度任务
        # 同步模式下，如果启用了立即检查，则直接执行超时任务
        if is_eager_mode:
            logger.info("运行在同步模式下，检查是否有需要立即执行的任务")
            for task in active_tasks:
                if task.last_executed_at is None:
                    logger.info(f"任务 {task.name} 从未执行过，立即执行")
                    execute_scheduled_task.delay(task.id)  # 使用delay确保异步调用
                else:
                    # 计算时间差（秒）
                    time_diff = (now - task.last_executed_at).total_seconds()
                    # 如果超过300秒（5分钟）没有执行，立即执行
                    if time_diff > 300:
                        logger.info(f"任务 {task.name} 已超过5分钟未执行，立即执行")
                        execute_scheduled_task.delay(task.id)  # 使用delay确保异步调用
                    else:
                        logger.info(f"任务 {task.name} 最近5分钟内已执行过，跳过")
        
        return {
            'status': 'success',
            'scheduled_tasks': scheduled_count,
            'removed_tasks': removed_count,
            'total_active_tasks': len(active_tasks)
        }
        
    except Exception as e:
        logger.error(f"检查和调度定时任务失败: {str(e)}", exc_info=True)
        return {
            'status': 'failure',
            'error': str(e)
        }


@shared_task(bind=True)
def execute_scheduled_task(self, task_id):
    """
    执行指定的定时任务
    在异步模式下，将由Celery Worker执行
    """
    execution_id = self.request.id  # 获取任务执行ID
    if TASK_DEBUG_MODE:
        logger.debug(f"开始执行任务 {task_id} (执行ID: {execution_id})")
        logger.debug(f"当前任务执行模式: {'同步' if app.conf.task_always_eager else '异步'}")
    
    log_entry = None
    task = None
    
    try:
        # 获取任务
        task = ScheduledTask.objects.get(pk=task_id)
        
        # 检查任务是否激活
        if not task.is_active:
            logger.warning(f"跳过执行已禁用的任务: {task.name} (ID: {task_id})")
            return {
                'status': 'skipped',
                'reason': 'task_disabled',
                'task_id': task_id
            }
        
        logger.info(f"开始执行定时任务: {task.name} (ID: {task_id})")
        
        # 创建执行日志
        log_entry = TaskExecutionLog.objects.create(
            task=task,
            start_time=timezone.now(),
            is_success=False,
            celery_task_id=execution_id
        )
        
        if TASK_DEBUG_MODE:
            logger.debug(f"已创建执行日志: {log_entry.id} 对应任务: {task.name}")
        
        # 执行任务逻辑
        # 这里可以根据任务类型执行不同的逻辑
        # 目前我们假设所有任务都执行collect_and_push_pending_items类似的逻辑
        
        # 导入并执行任务逻辑
        from tasks.tasks import collect_and_push_pending_items
        result = collect_and_push_pending_items()
        
        if TASK_DEBUG_MODE:
            logger.debug(f"任务执行结果: {result}")
        
        # 更新执行日志
        log_entry.end_time = timezone.now()
        log_entry.is_success = True
        log_entry.log_content = f'自动执行成功\n执行时间: {log_entry.start_time.strftime("%Y-%m-%d %H:%M:%S")}\n执行结果: {result}'
        log_entry.total_processed = result.get('total_processed', 0)
        log_entry.success_count = result.get('success_count', 0)
        log_entry.failure_count = result.get('failure_count', 0)
        log_entry.save()
        
        # 更新任务最后执行信息
        task.last_executed_at = timezone.now()
        task.last_execution_status = True
        task.last_execution_log = f'自动执行成功，处理了{result.get("total_processed", 0)}个项目'
        task.celery_task_id = execution_id  # 记录Celery任务ID
        task.save()
        
        execution_time = (log_entry.end_time - log_entry.start_time).total_seconds()
        logger.info(f"定时任务执行成功: {task.name} (耗时: {execution_time:.2f}秒)")
        
        return {
            'status': 'success',
            'task_id': task_id,
            'task_name': task.name,
            'execution_id': execution_id,
            'execution_time': execution_time,
            'result': result
        }
        
    except ScheduledTask.DoesNotExist:
        logger.error(f"任务不存在: {task_id}")
        return {
            'status': 'failure',
            'error': f'task_not_found: {task_id}',
            'execution_id': execution_id
        }
    except Exception as e:
        # 记录详细错误信息
        error_msg = str(e)
        logger.error(f"执行定时任务失败: {error_msg}", exc_info=True)
        
        # 如果出错，尝试更新日志
        try:
            if log_entry:
                log_entry.end_time = timezone.now()
                log_entry.is_success = False
                log_entry.error_message = error_msg
                log_entry.log_content = f'执行失败\n错误信息: {error_msg}'
                log_entry.save()
            
            # 尝试更新任务信息
            if task:
                task.last_executed_at = timezone.now()
                task.last_execution_status = False
                task.last_execution_log = f'自动执行失败：{error_msg}'
                task.save()
        except Exception as update_error:
            logger.error(f"更新任务状态失败: {str(update_error)}")
        
        return {
            'status': 'failure',
            'error': error_msg,
            'execution_id': execution_id,
            'task_id': task_id if task else None,
            'task_name': task.name if task else None
        }
